跟着LearnOpenGL学习3

您所在的位置:网站首页 qt opengl双缓冲 跟着LearnOpenGL学习3

跟着LearnOpenGL学习3

2023-05-15 20:21| 来源: 网络整理| 查看: 265

文章目录一、前言二、元素缓冲对象三、完整代码四、绘制模式

一、前言

通过跟着LearnOpenGL学习2–三角形绘制一文,我们已经知道了怎么配置渲染管线,来绘制三角形;

OpenGL主要处理三角形,当我们需要绘制别的图形时,例如:四边形,应当用三角形去拼接,组成我们想要的四边形;

二、元素缓冲对象

元素缓冲对象(Element Buffer Object,EBO),也叫索引缓冲对象(Index Buffer Object,IBO)

假设我们不再绘制一个三角形,而是绘制一个矩形。我们可以绘制两个三角形来组成一个矩形(OpenGL主要处理三角形)。

顶点数据如下:

float vertices[] = { // 第一个三角形 0.5f, 0.5f, 0.0f, // 右上角 0.5f, -0.5f, 0.0f, // 右下角 -0.5f, 0.5f, 0.0f, // 左上角 // 第二个三角形 0.5f, -0.5f, 0.0f, // 右下角 -0.5f, -0.5f, 0.0f, // 左下角 -0.5f, 0.5f, 0.0f // 左上角 };一个矩形只有4个而不是6个顶点,可以看到,我们指定了右下角和左上角两次;这样就产生50%的额外开销,当我们有包括上千个三角形的模型之后,这个问题会更糟糕,这会产生一大堆浪费;

更好的解决方案是只储存不同的顶点,并设定绘制这些顶点的顺序;这样子我们只要储存4个顶点就能绘制矩形了,之后只要指定绘制的顺序就行了;

元素缓冲区对象的工作方式正是如此,EBO是一个缓冲区,就像一个顶点缓冲区对象一样,它存储 OpenGL 用来决定要绘制哪些顶点的索引,这种所谓的索引绘制(Indexed Drawing)正是我们问题的解决方案;

定义(不重复的)顶点,和绘制出矩形所需的索引:

float vertices[] = { 0.5f, 0.5f, 0.0f, // 右上角 0.5f, -0.5f, 0.0f, // 右下角 -0.5f, -0.5f, 0.0f, // 左下角 -0.5f, 0.5f, 0.0f // 左上角 }; unsigned int indices[] = { // 注意索引从0开始! // 此例的索引(0,1,2,3)就是顶点数组vertices的下标, // 这样可以由下标代表顶点组合成矩形 0, 1, 3, // 第一个三角形 1, 2, 3 // 第二个三角形 };

创建元素缓冲对象

unsigned int EBO; glGenBuffers(1, &EBO);

绑定EBO到GL_ELEMENT_ARRAY_BUFFER缓冲区

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);

把索引复制到GL_ELEMENT_ARRAY_BUFFER缓冲区

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

绘制三角形

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

注意:用glDrawElements函数来绘制,而不是glDrawArrays函数;

第一个参数指定了我们绘制的模式,GL_TRIANGLES表示我们要绘制三角形;第二个参数是我们打算绘制顶点的个数,这里填6,也就是说我们一共需要绘制6个顶点;第三个参数是索引的类型,这里是GL_UNSIGNED_INT;最后一个参数里我们可以指定EBO中的偏移量(或者传递一个索引数组,但是这是当你不在使用索引缓冲对象的时候),但是我们会在这里填写0;

glDrawElements函数从当前绑定到GL_ELEMENT_ARRAY_BUFFER目标的EBO中获取其索引。这意味着我们每次想要使用索引渲染对象时都必须绑定相应的EBO,这又有点麻烦。碰巧顶点数组对象也跟元素缓冲区对象绑定。在绑定VAO时,绑定的最后一个元素缓冲区对象存储为VAO的元素缓冲区对象。然后,绑定到VAO也会自动绑定该EBO。

最后的初始化和绘制代码现在看起来像这样:

// ..:: 初始化代码 :: .. // 1. 绑定顶点数组对象 glBindVertexArray(VAO); // 2. 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用 glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 3. 复制我们的索引数组到一个索引缓冲中,供OpenGL使用 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 4. 设定顶点属性指针 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); [...] // ..:: 绘制代码(渲染循环中) :: .. glUseProgram(shaderProgram); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindVertexArray(0);三、完整代码

跟着LearnOpenGL学习3--四边形绘制_数组

#include "mainwindow.h" #include //在包含GLFW的头文件之前包含了GLAD的头文件; //GLAD的头文件包含了正确的OpenGL头文件(例如GL/gl.h); //所以需要在其它依赖于OpenGL的头文件之前包含GLAD; #include #include #include void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); // settings const unsigned int SCR_WIDTH = 800; const unsigned int SCR_HEIGHT = 600; const char *vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "void main()\n" "{\n" " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" "}\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0"; int main(int argc, char *argv[]) { QApplication a(argc, argv); //MainWindow w; //w.show(); //初始化GLFW //-------------------- glfwInit(); //配置GLFW //-------------------- //告诉GLFW使用的OpenGL本是3.3 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); //告诉GLFW使用的是核心模式(Core-profile) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //创建一个新的OpenGL环境和窗口 //----------------------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3